package accessstruct.lsss;

/**
 * @Classname LSSSLW10Engine
 * @Description
 * @Date 2024/3/6 21:20
 * @Created by kevin
 */
import accessstruct.AccessControlParameter;
import accessstruct.AccessTreeNode;
import accessstruct.lsss.LSSSPolicyEngine;
import accessstruct.lsss.LSSSPolicyParameter;
import accessstruct.parser.BinaryTreeNode;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * Created by Weiran Liu on 2016/7/20.
 *
 * This is the implementation of the linear secret sharing scheme proposed by Lewko and Waters in 2010.
 * Conference version: A. Lewko, B. Waters. Decentralizing attribute-based encryption. EUROCRYPT 2011, 568-588.
 * Full version: A. Lewko, B. Waters. Decentralizing attribute-based encryption. IACR Cryptology ePrint Achieve, 351, 2010.
 *
 * The original version of this code is written by the colleague of Cong Li,
 * which can be downloaded at https://github.com/cleverli2008/ABE.
 * I rewrite the code to meet my code architecture.
 */
public class LSSSLW10Engine  extends LSSSPolicyEngine{
    public static final String SCHEME_NAME = "Lewko-Waters-10 linear secret-sharing scheme";

    private static LSSSLW10Engine instance = new LSSSLW10Engine();

    private LSSSLW10Engine() {

    }

    public static LSSSLW10Engine getInstance() {
        return instance;
    }

    public String getEngineName() {
        return SCHEME_NAME;
    }

    public boolean isSupportThresholdGate() {
        return false;
    }

    /**
     *
     * @param accessPolicy 访问策略
     * @param rhos  属性
     * @return  返回一个生成用来秘密共享的参数AccessControlParameter
     */
    public static AccessControlParameter generateAccessControl(int[][] accessPolicy, String[] rhos) {
        //init access tree 生成访问树
        AccessTreeNode rootAccessTreeNode = AccessTreeNode.GenerateAccessTree(accessPolicy, rhos);
        //reconstruct binary tree node 重建一个二叉树
        BinaryTreeNode rootBinaryTreeNode = BinaryTreeNode.ReconstructBinaryTreeNode(accessPolicy, rhos);

        //generate lsss matrix
        //生成lsss矩阵
        Map<String, LinkedList<LinkedList<Integer>>> map = new LinkedHashMap<String, LinkedList<LinkedList<Integer>>>();
        int maxLen = 0;
        int rows = 0;
        // 维护全局计数器变量c，初始化为1
        int c = 1;
        LinkedList<Integer> vector = new LinkedList<Integer>();
        // 从根节点开始，使用向量(1)标记根节点（一个长度为1的向量）
        vector.add(1);
        rootBinaryTreeNode.setVector(vector);

        LinkedList<BinaryTreeNode> queue = new LinkedList<BinaryTreeNode>();
        queue.add(rootBinaryTreeNode);

        while (!queue.isEmpty()) {
            BinaryTreeNode p = queue.removeFirst();
            if (p.getType() == BinaryTreeNode.NodeType.AND) {
                // 如果父节点是一个标记为AND的门，使用向量v标记右子节点
                int size = p.getVector().size();
                LinkedList<Integer> pv = new LinkedList<Integer>();
                // 如果v的长度小于c，则在末尾用0填充v，使其长度为c
                if (size < c) {
                    pv.addAll(p.getVector());
                    for (int i = 0; i < c - size; i++) {
                        pv.add(0);
                    }
                } else {
                    pv.addAll(p.getVector());
                }
                // 标记右子节点
                BinaryTreeNode right = p.getRight();
                LinkedList<Integer> lv = new LinkedList<Integer>();
                lv.addAll(pv);
                lv.addLast(1);
                right.setVector(lv);
                queue.add(right);

                // 标记左子节点
                BinaryTreeNode left = p.getLeft();
                LinkedList<Integer> rv = new LinkedList<Integer>();
                for (int i = 0; i < c; i++) {
                    rv.add(0);
                }
                rv.addLast(-1);
                left.setVector(rv);
                queue.add(left);
                // 计数器c加1
                c += 1;
            } else if (p.getType() == BinaryTreeNode.NodeType.OR) {
                // 如果父节点是一个标记为OR的门，左右子节点使用相同的向量v进行标记
                BinaryTreeNode left = p.getLeft();
                LinkedList<Integer> lv = new LinkedList<Integer>();
                //then we also label its (left) children by v (and the value of c stays the same)
                lv.addAll(p.getVector());
                left.setVector(lv);
                queue.add(left);

                BinaryTreeNode right = p.getRight();
                LinkedList<Integer> rv = new LinkedList<Integer>();
                //then we also label its (right) children by v (and the value of c stays the same)
                rv.addAll(p.getVector());
                right.setVector(rv);
                queue.add(right);
            } else {
                // 叶子节点
                rows += 1;
                int size = p.getVector().size();
                maxLen = size > maxLen ? size : maxLen;
                if (map.containsKey(p.getValue())) {
                    map.get(p.getValue()).add(p.getVector());
                } else {
                    LinkedList<LinkedList<Integer>> list = new LinkedList<LinkedList<Integer>>();
                    list.add(p.getVector());
                    map.put(p.getValue(), list);
                }
            }
        }
        // 对每个向量进行填充，使其长度为maxLen
        for (Map.Entry<String, LinkedList<LinkedList<Integer>>> entry : map
                .entrySet()) {
            LinkedList<LinkedList<Integer>> v = entry.getValue();
            for (LinkedList<Integer> aV : v) {
                int size = aV.size();
                if (size < maxLen) {
                    for (int j = 0; j < maxLen - size; j++) {
                        aV.add(0);
                    }
                }
            }
        }

        // 构建LSSS矩阵
        int[][] lsssMatrix = new int[rows][];
        String[] rhosParameter = new String[rhos.length];
        int i = 0;
        for (Map.Entry<String, LinkedList<LinkedList<Integer>>> entry : map.entrySet()) {
            LinkedList<LinkedList<Integer>> v = entry.getValue();
            for (LinkedList<Integer> aV : v) {
                rhosParameter[i] = entry.getKey();
                lsssMatrix[i] = new int[maxLen];
                for (int k = 0; k < maxLen; k++) {
                    lsssMatrix[i][k] = aV.get(k);
                }
                i += 1;
            }
        }
        return new LSSSPolicyParameter(rootAccessTreeNode, accessPolicy, lsssMatrix, rhosParameter);
    }
}
